From c0b7c3321d15daf05a26818745367051300ac176 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 17 Mar 2012 02:17:23 +0100 Subject: [PATCH] css: Add GtkCssMatcher This is so we can later do matching with other things than GtkWidgetPath. In particular, this is a requirement for getting rid of GtkWidgetPath. --- gtk/Makefile.am | 2 + gtk/gtkcssmatcher.c | 174 ++++++++++++++++++++++++++++++++++ gtk/gtkcssmatcherprivate.h | 61 ++++++++++++ gtk/gtkcssselector.c | 188 +++++++++++++------------------------ 4 files changed, 301 insertions(+), 124 deletions(-) create mode 100644 gtk/gtkcssmatcher.c create mode 100644 gtk/gtkcssmatcherprivate.h diff --git a/gtk/Makefile.am b/gtk/Makefile.am index e062c9ad29..7559239ae5 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -431,6 +431,7 @@ gtk_private_h_sources = \ gtkcssimageurlprivate.h \ gtkcssimagewin32private.h \ gtkcsslookupprivate.h \ + gtkcssmatcherprivate.h \ gtkcssparserprivate.h \ gtkcssproviderprivate.h \ gtkcsssectionprivate.h \ @@ -627,6 +628,7 @@ gtk_base_c_sources = \ gtkcssimageurl.c \ gtkcssimagewin32.c \ gtkcsslookup.c \ + gtkcssmatcher.c \ gtkcssparser.c \ gtkcssprovider.c \ gtkcsssection.c \ diff --git a/gtk/gtkcssmatcher.c b/gtk/gtkcssmatcher.c new file mode 100644 index 0000000000..583b80301e --- /dev/null +++ b/gtk/gtkcssmatcher.c @@ -0,0 +1,174 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkcssmatcherprivate.h" + +#include "gtkwidgetpath.h" + +void +_gtk_css_matcher_init (GtkCssMatcher *matcher, + const GtkWidgetPath *path, + GtkStateFlags state) +{ + matcher->path = path; + matcher->state_flags = state; + matcher->index = gtk_widget_path_length (path) - 1; + matcher->sibling_index = gtk_widget_path_iter_get_sibling_index (path, matcher->index); +} + +gboolean +_gtk_css_matcher_get_parent (GtkCssMatcher *matcher, + const GtkCssMatcher *child) +{ + if (child->index == 0) + return FALSE; + + matcher->path = child->path; + matcher->state_flags = 0; + matcher->index = child->index - 1; + matcher->sibling_index = gtk_widget_path_iter_get_sibling_index (matcher->path, matcher->index); + + return TRUE; +} + +gboolean +_gtk_css_matcher_get_previous (GtkCssMatcher *matcher, + const GtkCssMatcher *next) +{ + if (next->sibling_index == 0) + return FALSE; + + matcher->path = next->path; + matcher->state_flags = 0; + matcher->index = next->index; + matcher->sibling_index = next->sibling_index - 1; + + return TRUE; +} + +gboolean +_gtk_css_matcher_has_state (const GtkCssMatcher *matcher, + GtkStateFlags state_flags) +{ + return (matcher->state_flags & state_flags) == state_flags; +} + +gboolean +_gtk_css_matcher_has_name (const GtkCssMatcher *matcher, + const char *name) +{ + const GtkWidgetPath *siblings; + GType type; + + type = g_type_from_name (name); + siblings = gtk_widget_path_iter_get_siblings (matcher->path, matcher->index); + if (siblings && matcher->sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path, matcher->index)) + return g_type_is_a (gtk_widget_path_iter_get_object_type (siblings, matcher->sibling_index), type); + else + return g_type_is_a (gtk_widget_path_iter_get_object_type (matcher->path, matcher->index), type); +} + +gboolean +_gtk_css_matcher_has_class (const GtkCssMatcher *matcher, + const char *class_name) +{ + const GtkWidgetPath *siblings; + + siblings = gtk_widget_path_iter_get_siblings (matcher->path, matcher->index); + if (siblings && matcher->sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path, matcher->index)) + return gtk_widget_path_iter_has_class (siblings, matcher->sibling_index, class_name); + else + return gtk_widget_path_iter_has_class (matcher->path, matcher->index, class_name); +} + +gboolean +_gtk_css_matcher_has_id (const GtkCssMatcher *matcher, + const char *id) +{ + const GtkWidgetPath *siblings; + + siblings = gtk_widget_path_iter_get_siblings (matcher->path, matcher->index); + if (siblings && matcher->sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path, matcher->index)) + return gtk_widget_path_iter_has_name (siblings, matcher->sibling_index, id); + else + return gtk_widget_path_iter_has_name (matcher->path, matcher->index, id); +} + +gboolean +_gtk_css_matcher_has_regions (const GtkCssMatcher *matcher) +{ + const GtkWidgetPath *siblings; + GSList *regions; + gboolean result; + + siblings = gtk_widget_path_iter_get_siblings (matcher->path, matcher->index); + if (siblings && matcher->sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path, matcher->index)) + regions = gtk_widget_path_iter_list_regions (siblings, matcher->sibling_index); + else + regions = gtk_widget_path_iter_list_regions (matcher->path, matcher->index); + result = regions != NULL; + g_slist_free (regions); + + return result; +} + +gboolean +_gtk_css_matcher_has_region (const GtkCssMatcher *matcher, + const char *region, + GtkRegionFlags flags) +{ + const GtkWidgetPath *siblings; + GtkRegionFlags region_flags; + + siblings = gtk_widget_path_iter_get_siblings (matcher->path, matcher->index); + if (siblings && matcher->sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path, matcher->index)) + { + if (!gtk_widget_path_iter_has_region (siblings, matcher->sibling_index, region, ®ion_flags)) + return FALSE; + } + else + { + if (!gtk_widget_path_iter_has_region (matcher->path, matcher->index, region, ®ion_flags)) + return FALSE; + } + + if ((flags & region_flags) != flags) + return FALSE; + + return TRUE; +} + +guint +_gtk_css_matcher_get_sibling_index (const GtkCssMatcher *matcher) +{ + return matcher->sibling_index; +} + +guint +_gtk_css_matcher_get_n_siblings (const GtkCssMatcher *matcher) +{ + const GtkWidgetPath *siblings; + + siblings = gtk_widget_path_iter_get_siblings (matcher->path, matcher->index); + if (!siblings) + return 0; + + return gtk_widget_path_length (siblings); +} + diff --git a/gtk/gtkcssmatcherprivate.h b/gtk/gtkcssmatcherprivate.h new file mode 100644 index 0000000000..61988a296b --- /dev/null +++ b/gtk/gtkcssmatcherprivate.h @@ -0,0 +1,61 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GTK_CSS_MATCHER_PRIVATE_H__ +#define __GTK_CSS_MATCHER_PRIVATE_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GtkCssMatcher GtkCssMatcher; + +struct _GtkCssMatcher { + const GtkWidgetPath *path; + GtkStateFlags state_flags; + guint index; + guint sibling_index; +}; + +void _gtk_css_matcher_init (GtkCssMatcher *matcher, + const GtkWidgetPath *path, + GtkStateFlags state); +gboolean _gtk_css_matcher_get_parent (GtkCssMatcher *matcher, + const GtkCssMatcher *child); +gboolean _gtk_css_matcher_get_previous (GtkCssMatcher *matcher, + const GtkCssMatcher *next); + +gboolean _gtk_css_matcher_has_state (const GtkCssMatcher *matcher, + GtkStateFlags state_flags); +gboolean _gtk_css_matcher_has_name (const GtkCssMatcher *matcher, + const char *name); +gboolean _gtk_css_matcher_has_class (const GtkCssMatcher *matcher, + const char *class_name); +gboolean _gtk_css_matcher_has_id (const GtkCssMatcher *matcher, + const char *id); +gboolean _gtk_css_matcher_has_regions (const GtkCssMatcher *matcher); +gboolean _gtk_css_matcher_has_region (const GtkCssMatcher *matcher, + const char *region, + GtkRegionFlags flags); +guint _gtk_css_matcher_get_sibling_index + (const GtkCssMatcher *matcher); +guint _gtk_css_matcher_get_n_siblings (const GtkCssMatcher *matcher); + +G_END_DECLS + +#endif /* __GTK_CSS_MATCHER_PRIVATE_H__ */ diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c index 2f7735d8eb..746394918f 100644 --- a/gtk/gtkcssselector.c +++ b/gtk/gtkcssselector.c @@ -21,9 +21,9 @@ #include +#include "gtkcssmatcherprivate.h" #include "gtkcssprovider.h" #include "gtkstylecontextprivate.h" -#include "gtkwidgetpath.h" typedef struct _GtkCssSelectorClass GtkCssSelectorClass; @@ -33,10 +33,7 @@ struct _GtkCssSelectorClass { void (* print) (const GtkCssSelector *selector, GString *string); gboolean (* match) (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling); + const GtkCssMatcher *matcher); guint increase_id_specificity :1; guint increase_class_specificity :1; @@ -53,15 +50,12 @@ struct _GtkCssSelector static gboolean gtk_css_selector_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { if (selector == NULL) return TRUE; - return selector->class->match (selector, state, path, id, sibling); + return selector->class->match (selector, matcher); } static const GtkCssSelector * @@ -83,18 +77,15 @@ gtk_css_selector_descendant_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_descendant_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - while (id-- > 0) + GtkCssMatcher ancestor; + + while (_gtk_css_matcher_get_parent (&ancestor, matcher)) { - if (gtk_css_selector_match (gtk_css_selector_previous (selector), - 0, - path, - id, - gtk_widget_path_iter_get_sibling_index (path, id))) + matcher = &ancestor; + + if (gtk_css_selector_match (gtk_css_selector_previous (selector), matcher)) return TRUE; } @@ -119,19 +110,14 @@ gtk_css_selector_child_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_child_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - if (id == 0) + GtkCssMatcher parent; + + if (!_gtk_css_matcher_get_parent (&parent, matcher)) return FALSE; - return gtk_css_selector_match (gtk_css_selector_previous (selector), - 0, - path, - id - 1, - gtk_widget_path_iter_get_sibling_index (path, id - 1)); + return gtk_css_selector_match (gtk_css_selector_previous (selector), &parent); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = { @@ -152,18 +138,15 @@ gtk_css_selector_sibling_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_sibling_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - while (sibling-- > 0) + GtkCssMatcher previous; + + while (_gtk_css_matcher_get_previous (&previous, matcher)) { - if (gtk_css_selector_match (gtk_css_selector_previous (selector), - 0, - path, - id, - sibling)) + matcher = &previous; + + if (gtk_css_selector_match (gtk_css_selector_previous (selector), matcher)) return TRUE; } @@ -188,19 +171,14 @@ gtk_css_selector_adjacent_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_adjacent_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - if (sibling == 0) + GtkCssMatcher previous; + + if (!_gtk_css_matcher_get_previous (&previous, matcher)) return FALSE; - return gtk_css_selector_match (gtk_css_selector_previous (selector), - 0, - path, - id, - sibling - 1); + return gtk_css_selector_match (gtk_css_selector_previous (selector), &previous); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = { @@ -221,24 +199,19 @@ gtk_css_selector_any_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_any_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { const GtkCssSelector *previous = gtk_css_selector_previous (selector); - GSList *regions; if (previous && previous->class == >K_CSS_SELECTOR_DESCENDANT && - (regions = gtk_widget_path_iter_list_regions (path, id)) != NULL) + _gtk_css_matcher_has_regions (matcher)) { - g_slist_free (regions); - if (gtk_css_selector_match (gtk_css_selector_previous (previous), state, path, id, sibling)) + if (gtk_css_selector_match (gtk_css_selector_previous (previous), matcher)) return TRUE; } - return gtk_css_selector_match (previous, state, path, id, sibling); + return gtk_css_selector_match (previous, matcher); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_ANY = { @@ -259,17 +232,12 @@ gtk_css_selector_name_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_name_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - GType type = g_type_from_name (selector->data); - - if (!g_type_is_a (gtk_widget_path_iter_get_object_type (path, id), type)) + if (!_gtk_css_matcher_has_name (matcher, selector->data)) return FALSE; - return gtk_css_selector_match (gtk_css_selector_previous (selector), state, path, id, sibling); + return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_NAME = { @@ -290,22 +258,19 @@ gtk_css_selector_region_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_region_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { const GtkCssSelector *previous; - if (!gtk_widget_path_iter_has_region (path, id, selector->data, NULL)) + if (!_gtk_css_matcher_has_region (matcher, selector->data, 0)) return FALSE; previous = gtk_css_selector_previous (selector); if (previous && previous->class == >K_CSS_SELECTOR_DESCENDANT && - gtk_css_selector_match (gtk_css_selector_previous (previous), state, path, id, sibling)) + gtk_css_selector_match (gtk_css_selector_previous (previous), matcher)) return TRUE; - return gtk_css_selector_match (previous, state, path, id, sibling); + return gtk_css_selector_match (previous, matcher); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_REGION = { @@ -327,15 +292,12 @@ gtk_css_selector_class_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_class_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - if (!gtk_widget_path_iter_has_class (path, id, selector->data)) + if (!_gtk_css_matcher_has_class (matcher, selector->data)) return FALSE; - return gtk_css_selector_match (gtk_css_selector_previous (selector), state, path, id, sibling); + return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_CLASS = { @@ -357,15 +319,12 @@ gtk_css_selector_id_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_id_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - if (!gtk_widget_path_iter_has_name (path, id, selector->data)) + if (!_gtk_css_matcher_has_id (matcher, selector->data)) return FALSE; - return gtk_css_selector_match (gtk_css_selector_previous (selector), state, path, id, sibling); + return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_ID = { @@ -409,15 +368,12 @@ gtk_css_selector_pseudoclass_state_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_pseudoclass_state_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - if (!(GPOINTER_TO_UINT (selector->data) & state)) + if (!_gtk_css_matcher_has_state (matcher, GPOINTER_TO_UINT (selector->data))) return FALSE; - return gtk_css_selector_match (gtk_css_selector_previous (selector), state, path, id, sibling); + return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_PSEUDOCLASS_STATE = { @@ -460,53 +416,43 @@ gtk_css_selector_pseudoclass_region_print (const GtkCssSelector *selector, static gboolean gtk_css_selector_pseudoclass_region_match_for_region (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { - GtkRegionFlags selector_flags, path_flags; + GtkRegionFlags selector_flags; const GtkCssSelector *previous; selector_flags = GPOINTER_TO_UINT (selector->data); selector = gtk_css_selector_previous (selector); - if (!gtk_widget_path_iter_has_region (path, id, selector->data, &path_flags)) - return FALSE; - - if ((selector_flags & path_flags) != selector_flags) + if (!_gtk_css_matcher_has_region (matcher, selector->data, selector_flags)) return FALSE; previous = gtk_css_selector_previous (selector); if (previous && previous->class == >K_CSS_SELECTOR_DESCENDANT && - gtk_css_selector_match (gtk_css_selector_previous (previous), state, path, id, sibling)) + gtk_css_selector_match (gtk_css_selector_previous (previous), matcher)) return TRUE; - return gtk_css_selector_match (previous, state, path, id, sibling); + return gtk_css_selector_match (previous, matcher); } static gboolean gtk_css_selector_pseudoclass_region_match (const GtkCssSelector *selector, - GtkStateFlags state, - const GtkWidgetPath *path, - guint id, - guint sibling) + const GtkCssMatcher *matcher) { GtkRegionFlags region; - const GtkWidgetPath *siblings; - guint n_siblings; + guint sibling, n_siblings; const GtkCssSelector *previous; previous = gtk_css_selector_previous (selector); if (previous && previous->class == >K_CSS_SELECTOR_REGION) - return gtk_css_selector_pseudoclass_region_match_for_region (selector, state, path, id, sibling); + return gtk_css_selector_pseudoclass_region_match_for_region (selector, matcher); - siblings = gtk_widget_path_iter_get_siblings (path, id); - if (siblings == NULL) - return 0; + n_siblings = _gtk_css_matcher_get_n_siblings (matcher); + if (n_siblings == 0) + return FALSE; + sibling = _gtk_css_matcher_get_sibling_index (matcher); region = GPOINTER_TO_UINT (selector->data); - n_siblings = gtk_widget_path_length (siblings); switch (region) { @@ -537,7 +483,7 @@ gtk_css_selector_pseudoclass_region_match (const GtkCssSelector *selector, return FALSE; } - return gtk_css_selector_match (previous, state, path, id, sibling); + return gtk_css_selector_match (previous, matcher); } static const GtkCssSelectorClass GTK_CSS_SELECTOR_PSEUDOCLASS_REGION = { @@ -887,20 +833,14 @@ _gtk_css_selector_matches (const GtkCssSelector *selector, const GtkWidgetPath *path, GtkStateFlags state) { - guint length; + GtkCssMatcher matcher; g_return_val_if_fail (selector != NULL, FALSE); g_return_val_if_fail (path != NULL, FALSE); - length = gtk_widget_path_length (path); - if (length == 0) - return FALSE; + _gtk_css_matcher_init (&matcher, path, state); - return gtk_css_selector_match (selector, - state, - path, - length - 1, - gtk_widget_path_iter_get_sibling_index (path, length - 1)); + return gtk_css_selector_match (selector, &matcher); } /* Computes specificity according to CSS 2.1. -- 2.30.2